package mmi.gui.shape;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import mmi.gui.Application;

/**
 * Line is a wrapper for the Java provided Line but with a closed public interface
 * 
 * @author louis
 *
 */
public class Line extends Shape {

	Line2D line = null;

	public Line(int id, Point2D start, Point2D end, Color lineColour, Color fillColour, int lineWidth) {
		super(id, start, end, lineColour, fillColour, lineWidth);

		makeTheShape();
	}

	public Line(Point2D start, Point2D end, Color lineColour, Color fillColour, int lineWidth) {
		super(start, end, lineColour, fillColour, lineWidth);

		makeTheShape();
	}

	@Override
	public boolean contains(Point2D position) {
		if(line.ptLineDist(position) <= lineWidth ) {
			return true;
		}
		return false;
	}

	@Override
	public void draw(Graphics2D g) {
		Stroke s = g.getStroke();

		Color defaultColour = g.getColor();

		g.setStroke(new BasicStroke(lineWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER));
		g.setColor(lineColour);

		g.draw(line);

		g.setStroke(s);
		g.setColor(defaultColour);

		drawBoundingBox(g);
	}

	/**
	 * Draws a default bounding box. The default is to place 4 bounding boxes, in each corner one.
	 * For special bounding boxes per shape, override this function.
	 * @param g
	 */
	@Override
	public void drawBoundingBox(Graphics2D g)
	{
		if(showBoundingBox)
		{
			// right
			g.fillRect((int) (start.getX() - .5*Shape.getBoundingBoxSize()), (int) (start.getY() - .5*Shape.getBoundingBoxSize()), Shape.getBoundingBoxSize(), Shape.getBoundingBoxSize());

			// left
			g.fillRect((int) (end.getX() - .5*Shape.getBoundingBoxSize()), (int) (end.getY() - .5*Shape.getBoundingBoxSize()), Shape.getBoundingBoxSize(), Shape.getBoundingBoxSize());
		}

		if(showBoundingLines)
		{
			int leftX = (int) (start.getX() <= end.getX() ? start.getX() : end.getX());
			int rightX = (int) (start.getX() <= end.getX() ? end.getX() : start.getX());

			int topY = (int) (start.getY() <= end.getY() ? start.getY() : end.getY());
			int bottomY = (int) (start.getY() <= end.getY() ? end.getY() : start.getY());

			Stroke defaultStroke = g.getStroke();
			g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{9}, 0));

			// upper line
			g.drawLine(leftX, topY, rightX, topY);

			// right line
			g.drawLine(rightX, topY, rightX, bottomY);

			// bottom line
			g.drawLine(rightX, bottomY, leftX, bottomY);

			// left line
			g.drawLine(leftX, bottomY, leftX, topY);

			g.setStroke(defaultStroke);
		}
	}

	@Override
	public void fill(Graphics2D g) {
		Color defColour = g.getColor();
		if(fillColour == null) {
			g.setColor(Color.white);
		} else {
			g.setColor(fillColour);
		}
		g.fill(line);
		g.setColor(defColour);
	}

	@Override
	public Shapes getShape() {
		return Shapes.Line;
	}

	@Override
	public String getXMLRepresentation() {
		String s = "";

		s += "\t\t<Shape shapetype=\"Line\" id=\"" + id + "\">" + "\n";
		s += "\t\t\t<xstart>" + start.getX() + "</xstart>" + "\n";
		s += "\t\t\t<ystart>" + start.getY() + "</ystart>" + "\n";
		s += "\t\t\t<xend>" + end.getX() + "</xend>" + "\n";
		s += "\t\t\t<yend>" + end.getY() + "</yend>" + "\n";
		s += "\t\t\t<linecolour>" + lineColour + "</linecolour>" + "\n";
		s += "\t\t\t<fillcolour>" + fillColour + "</fillcolour>" + "\n";
		s += "\t\t\t<linewidth>" + lineWidth + "</linewidth>" + "\n";
		s += "\t\t</Shape>";

		return s;
	}

	/**
	 * Test if a position is corresponding to one of the bounding boxes
	 * @param position to test for a bounding box
	 * @return Side if position corresponds to a bounding box, otherwise null
	 */
	@Override
	public Sides isSide(Point2D position)
	{
		if(showBoundingBox)
		{
			Rectangle2D right = new Rectangle2D.Double(start.getX() - .5*Shape.getBoundingBoxSize(), start.getY() - .5*Shape.getBoundingBoxSize(), Shape.getBoundingBoxSize(), Shape.getBoundingBoxSize());
			if(right.contains(position))
			{
				Application.TraceDebug("R side click detected");
				return Sides.Right;
			}

			Rectangle2D left = new Rectangle2D.Double(end.getX() - .5*Shape.getBoundingBoxSize(), end.getY() - .5*Shape.getBoundingBoxSize(), Shape.getBoundingBoxSize(), Shape.getBoundingBoxSize());
			if(left.contains(position))
			{
				Application.TraceDebug("L side click detected");
				return Sides.Left;
			}
		}
		return null;
	}

	@Override
	public void makeTheShape()
	{
		line = new Line2D.Double(start.getX(), start.getY(), end.getX(), end.getY());
	}

	@Override
	public void resizeShape(Shape.Sides side, Double optionalXDif, Double optionalYDif)
	{
		double xdif = optionalXDif == null ? 0 : optionalXDif;
		double ydif = optionalYDif == null ? 0 : optionalYDif;

		switch (side) {
		case Right:
			start.setLocation(start.getX() + xdif, start.getY() + ydif);
			break;
		case Left:
			end.setLocation(end.getX() + xdif, end.getY() + ydif);
		default:
			break;
		}

		makeTheShape();
	}

	@Override
	public String toString() {
		String s = "";

		s += "Line [" + id + "]: " + start.getX() + " " + start.getY() + " " + end.getX() + " " + end.getY();

		return s;
	}

}
